<?php
/*
 * @Author       : chaihao
 * @Date         : 2020-09-16 18:08:26
 * @LastEditTime : 2020-10-23 16:19:32
 * @FilePath     : /ai/workerman/Applications/Chat/Events.php
 * @author: chaihao <chaihao0823@gmail.com>
 */

/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死，可以将下面declare打开（去掉//注释），并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */
//declare(ticks=1);

/**
 * 聊天主逻辑
 * 主要是处理 onMessage onClose 
 */

use \GatewayWorker\Lib\Gateway;

class Events
{

    public static $redis;
    public static $db;

    // /**
    //  * 获取redis实例化
    //  */
    public static function getRedis()
    {
        if (self::$redis == null) {
            $params = require('/var/www/html/ai/workerman/config/params.php');
            // $params = require('/Users/chaihao/project/xunao/ai/workerman/config/params.php');
            //             $params = require('D:/phpstudy_pro/WWW/ai/workerman/config/params.php');
            $redis = new \Redis();
            $redis->connect($params['redis']['hostname'], $params['redis']['port']); //连接Redis
            $redis->auth($params['redis']['password']); //密码验证
            $redis->select($params['redis']['database']); //选择数据库
            self::$redis = $redis;
        }
        return self::$redis;
    }

    public static function getDb()
    {
        require_once('Connection.php');
        if (self::$db == null) {
            //                $params = require('D:/phpstudy_pro/WWW/ai/workerman/config/params.php');
            // $params = require('/Users/chaihao/project/xunao/ai/workerman/config/params.php');
            $params = require('/var/www/html/ai/workerman/config/params.php');
            self::$db =  new \Workerman\MySQL\Connection($params['mysql']['host'], $params['mysql']['port'], $params['mysql']['user'], $params['mysql']['password'], $params['mysql']['db_name']);
        }
        return self::$db;
    }

    /**
     * 有消息时
     * @param int $client_id
     * @param mixed $message
     */
    public static function onMessage($client_id, $message)
    {
        // debug
        //echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id session:".json_encode($_SESSION)." onMessage:".$message."\n";
        echo $message . "\n";

        // 客户端传递的是json数据
        $message_data = json_decode($message, true);
        if (!$message_data) {
            return;
        }
        if (!in_array($message_data['type'], ['pong', 'C2S_Update_Program', 'C2S_Kick'])) {
            $token = $message_data['token'] ?? '';
            if (!empty($message_data['user_id'])) {
                $user_id = $message_data['user_id'];
            } else {
                $user_id = $_SESSION['user_id'] ?? '';
            }
            $re =  self::checkUser($user_id, $token);
            if (!$re) {
                $new_message = [
                    'status' => false,
                    'type' => 'S2C_LOGIN',
                    'message' => '登录失败',
                    // 'client_list' => array_values($clients_list), // 所有用户列表
                    'message' => '账户验证失败',
                ];
                Gateway::sendToCurrentClient(json_encode($new_message));
                return  self::onClose($client_id);
            }
        }
        // $default_blacklist_time = 3; //默认屏蔽用户发言时间，单位分钟
        // $default_room_disable_time = 86400; //默认直播间禁言时间，单位秒
        // 根据类型执行不同的业务
        switch ($message_data['type']) {
                // 客户端回应服务端的心跳
            case 'pong':
                // 获取当前用户绑定信息
                $result =  self::updateIvtCode($_SESSION);
                if (!$result) {
                    if (isset($_SESSION['room_id']) && !empty($_SESSION['room_id'])) {
                        self::exitRoom($_SESSION);
                        $not_in_room_client_id = self::getNotInRoomClient();
                        $all_message = [
                            'type' => 'S2C_NotInRoomUpdate',
                            'room_id' => intval($_SESSION['room_id']),
                            'curseat' => self::getAllRoom($_SESSION['room_id']),
                        ];
                        // 发送所有未进入房间的client_id
                        Gateway::sendToAll(json_encode($all_message), $not_in_room_client_id);
                    }

                    $userSeatInfo = self::getSeatInfo($_SESSION['room_id']);
                    $info = array_column($userSeatInfo, null, 'user_id');
                    if (isset($info[$_SESSION['user_id']])) {
                        self::seatUpdate(2, $_SESSION);
                        $seat_message = [
                            'type' => 'S2C_SelectSeatUpdate',
                            'col' => (int)$info[$_SESSION['user_id']]['col'],
                            'row' => (int) $info[$_SESSION['user_id']]['row'],
                            'client_name' => $_SESSION['client_name'],
                            'content' => '邀请码过期踢出',
                            'userinfo' => self::getUserInfo($_SESSION['user_id'])
                        ];
                        // 发送至当前房间的client_id
                        Gateway::sendToGroup($_SESSION['room_id'], json_encode($seat_message));
                    }
                }
                return;
                // {type: S2C_LOGIN,user_id: 1,client_name: username} 
            case 'C2S_LOGIN':
                // $redis = self::getRedis();
                // 把房间号昵称放到session中
                $client_name = htmlspecialchars($message_data['client_name']);
                // 获取房间内所有用户列表 
                // $clients_list = Gateway::getAllClientSessions();
                // foreach ($clients_list as $tmp_client_id => $item) {
                //     if (isset($item['client_id'])) {
                //         $clients_list[$item['client_id']] = $item;
                //     }
                // }
                // $clients_list[$client_id] = [
                //     'client_name' => $client_name,
                //     'client_id' => $client_id,
                //     'user_id' => $message_data['user_id'],
                // ];

                // 获取房间内所有用户列表 
                $clients_list = Gateway::getAllClientSessions();
                $user_list =  array_column($clients_list, 'client_id', 'user_id');

                if (isset($user_list[$user_id])) {
                    $new_message = [
                        'status' => false,
                        'type' => 'S2C_LOGIN',
                        'message' => '登录失败',
                        // 'client_list' => array_values($clients_list), // 所有用户列表
                        'message' => '账户已登录',
                    ];
                    Gateway::sendToCurrentClient(json_encode($new_message));
                    return  self::onClose($client_id);
                }
                $_SESSION['client_name'] = $client_name;
                $_SESSION['client_id'] = $client_id;
                $_SESSION['user_id'] = $message_data['user_id'];
                $_SESSION['room_id'] = '';
                $_SESSION['row'] = 0;
                $_SESSION['col'] = 0;
                // Gateway::sendToCurrentClient(json_encode($new_message));
                // $_SESSION['network_type'] = (isset($message_data['network_type']) && !empty($message_data['network_type'])) ? strtolower(trim($message_data['network_type'])) : '';
                $new_message = [
                    'status' => true,
                    'type' => 'S2C_LOGIN',
                    'message' => '登录成功',
                    'client_name' => $client_name,
                    // 'client_list' => array_values($clients_list), // 所有用户列表
                    'room_data' => self::getAllRoom(),
                ];
                return Gateway::sendToCurrentClient(json_encode($new_message));
                // {type: S2C_SelectSeat, room_id: 1,user_id: 1,status:1,row:1,col:1}   选择座位指令
            case 'C2S_SelectSeat': // 房间座位状态处理 -- 选座
                $room_id = $message_data['room_id'];
                $user_id = $message_data['user_id'];
                $row = $message_data['row'];
                $col = $message_data['col'];
                // 获取房间当前座位情况
                $userSeatInfo = self::getSeatInfo($_SESSION['room_id']);
                $info = array_column($userSeatInfo, null, 'user_id');
                if (isset($info[$user_id])) {
                    $_SESSION['row'] = $info[$user_id]['row'];
                    $_SESSION['col'] = $info[$user_id]['col'];
                    // 用户已选座，结束流程
                    return;
                }
                // status = 5 选座
                $result =  self::seatUpdate(5, $message_data);
                $_SESSION['row'] = $row;
                $_SESSION['col'] = $col;
                $clients_list = Gateway::getClientSessionsByGroup($room_id);
                var_export($clients_list);
                $new_message = [
                    'status' => true,
                    'type' => 'S2C_SelectSeat',
                    'message' => '选座成功',
                    'col' => (int)$col,
                    'row' => (int) $row,
                ];
                if ($result !== true) {
                    $new_message['status'] = false;
                    $new_message['message'] = $result;
                    return Gateway::sendToCurrentClient(json_encode($new_message));
                }
                $new_group_message = [
                    'type' => 'S2C_SelectSeatUpdate',
                    'client_name' => $_SESSION['client_name'],
                    'col' => (int)$col,
                    'row' => (int) $row,
                    'content' => '选座',
                    'userinfo' => self::getUserInfo($_SESSION['user_id'])
                ];
                Gateway::sendToGroup($room_id, json_encode($new_group_message));
                return Gateway::sendToCurrentClient(json_encode($new_message));
                // {type: S2C_SelectRoom, room_id: 1,user_id: 1,client_name:username} 
            case 'C2S_SelectRoom': //   选择房间指令
                if (empty($message_data['user_id'])) {
                    throw new \Exception("用户不存在 ");
                }
                $room_id = $message_data['room_id'];
                $user_id = $message_data['user_id'];
                $client_name = htmlspecialchars($message_data['client_name']);
                $db = self::getDb();
                $redis = self::getRedis();
                // 获取房间信息
                // $roomInfo = $db->select('ID, maxseat, curseat')->from('pltf.room')->where("ID=" . $room_id)->row();
                $roomInfo = $db->row("SELECT ID, maxseat, curseat,host FROM `pltf.room` WHERE ID=" . $room_id);;
                // 当前房间链接数
                $currentNum =  count(Gateway::getClientSessionsByGroup($room_id));
                if ($roomInfo['curseat']  <  $roomInfo['maxseat'] && $roomInfo['maxseat'] > 0 && $currentNum < $roomInfo['maxseat']) {
                    $roomInfo['curseat'] = ($currentNum + 1);
                } else {
                    $error = '加入房间失败';
                    return Gateway::sendToCurrentClient(json_encode(['status' => false, 'type' => 'S2C_SelectRoom', 'message' => $error]));
                }
                // 获取房间内所有用户列表 
                $clients_list = Gateway::getClientSessionsByGroup($room_id);

                foreach ($clients_list as $tmp_client_id => $item) {
                    $clients_list[$item['client_id']] = $item;
                }
                $clients_list[$client_id] = [
                    'room_id' => intval($room_id),
                    'client_name' => $client_name,
                    'client_id' => $client_id,
                    'user_id' => $message_data['user_id'],
                    'col' => 0,
                    'row' => 0,
                ];
                $_SESSION['room_id'] = $room_id;

                // 处理数据 添加数据至 seattimeline
                $seatTimeLine = [
                    'roomID' => $room_id,
                    'row' => 0,
                    'col' => 0,
                    'userID' => $message_data['user_id'],
                    'status' => 1,
                    'updatetime' => date('Y-m-d H:i:s', time())
                ];
                // $db->insert('pltf.seattimeline')->cols($seatTimeLine)->query();
                self::insertData('pltf.seattimeline', $seatTimeLine);
                // 更新数据
                // $room_up = $db->update('pltf.room')->cols(['curseat' => $roomInfo['curseat']])->where('ID=' . $room_id)->query();
                $room_up = $db->query("UPDATE `pltf.room` SET `curseat` ='" . $roomInfo['curseat'] . "' WHERE `ID`=" . $room_id);
                // 将 client_id 加入 room_id
                Gateway::joinGroup($client_id, $room_id);
                // 获取房间流
                $steamURL = $db->single("SELECT steamURL FROM `pltf.steaming` WHERE roomID=" . $room_id);
                // $new_group_message = [
                //     'type' => 'S2C_RoomUpdate',
                //     'client_id' => $client_id,
                //     'client_name' => $client_name,
                //     'time' => date('Y-m-d H:i:s'),
                //     'user_id' => $message_data['user_id'],
                //     'content' => $client_name . '进入房间',
                //     'clients_list' => $clients_list,
                //     'steaming' => $steamURL,
                //     'curseat' => $roomInfo['curseat'], // 房间人数
                //     'room_seat_info' => self::getSeatInfo($room_id), // 获取房间座位情况
                // ];
                // if (isset($message_data['user_id'])) {
                //     Gateway::sendToGroup($room_id, json_encode($new_group_message));
                // }

                $new_message = [
                    'status' => true,
                    'type' => 'S2C_SelectRoom',
                    'host' => $roomInfo['host'],
                    'room_data' => $roomInfo,
                    'steaming' => $steamURL,
                    'message' => '进入房间成功',
                    'room_seat_info' => self::getSeatInfo($room_id), // 获取房间座位情况
                ];
                $not_in_room_client_id = self::getNotInRoomClient();
                $all_message = [
                    'type' => 'S2C_NotInRoomUpdate',
                    'room_id' => intval($room_id),
                    'curseat' => self::getAllRoom($room_id),
                ];
                // 发送所有未进入房间的client_id
                Gateway::sendToAll(json_encode($all_message), $not_in_room_client_id, $client_id);
                return Gateway::sendToCurrentClient(json_encode($new_message));
            case 'C2S_SendCard': // 发送名片
                //获取redis和数据库实例
                $db = self::getDb();
                $to_user_id = $message_data['to_user_id'];
                $allData =  Gateway::getAllClientSessions();
                $dataInfo = array_column($allData, 'client_id', 'user_id');
                if (isset($dataInfo[$to_user_id])) {
                    $to_client_id = $dataInfo[$to_user_id]; // 接收名片client_ids
                    $client_name = $_SESSION['client_name'];
                    $user_id = $_SESSION['user_id'];
                    // 获取当前用户信息信息
                    // $userData = $db->select("Name,Company,Position,email,Cellphone,EnglishName,EnglishCompany,EnglishPosition")->from('user.user')->where("ID = " . $user_id)->row();
                    $userData = $db->row("SELECT `Name`,Company,Position,email,Cellphone,EnglishName,EnglishCompany,EnglishPosition FROM `user.user` WHERE ID = " . $user_id);
                    // 获取名片样式
                    $card_style = $db->single("SELECT style FROM `pltf.card` WHERE userID=" . $user_id);
                    // 添加发送记录
                    $sendData = [
                        'fromID' => $user_id,
                        'toID' => $to_user_id,
                        'type' =>  $card_style,
                        'name' => !empty($userData['Name']) ? $userData['Name'] : NULL,
                        'company' => !empty($userData['Company']) ? $userData['Company'] :  NULL,
                        'position' => !empty($userData['company']) ? $userData['company'] : NULL,
                        'email' => empty($userData['email']) ? '-' : $userData['email'],
                        'phone' => empty($userData['Cellphone']) ? '-' : $userData['Cellphone'],
                        'updatetime' => date('Y-m-d H:i:s', time()),
                        'ENname'  => empty($userData['EnglishName']) ? NULL : $userData['EnglishName'],
                        'ENcompany' => empty($userData['EnglishCompany']) ? NULL : $userData['EnglishCompany'],
                        'ENname'  => empty($userData['EnglishPosition']) ? NULL : $userData['EnglishPosition'],
                    ];

                    // $db->insert('pltf.sendcard')->cols($sendData)->query();
                    self::insertData('pltf.sendcard', $sendData);
                    $new_message = [
                        'type' => 'S2C_SendCard',
                        'from_client_id' => $client_id,
                        'from_client_name' => $client_name,
                        'from_userinfo' => self::getUserInfo($user_id),
                        'from_card_type' => $message_data['card_type'],
                        'time' => date('Y-m-d H:i:s'),
                    ];
                    // 消息发送至接受客户
                    return Gateway::sendToClient($to_client_id, json_encode($new_message));
                }
            case 'C2S_Animation': //    鼓掌等动作指令
                $room_id = $message_data['room_id'];
                // 添加数据
                $insertData = [
                    'status' => $message_data['status'],
                    'row' => (int) $message_data['row'],
                    'col' => (int)$message_data['col'],
                    'roomID' => $message_data['room_id'],
                    'userID' => $message_data['user_id'],
                    'updatetime' => date('Y-m-d H:i:s', time()),
                ];
                self::insertData('pltf.animation', $insertData);
                $new_group_message = [
                    'type' => 'S2C_Animation',
                    'status' => $message_data['status'],
                    'row' => (int) $message_data['row'],
                    'col' => (int)$message_data['col'],
                    'room_id' => intval($message_data['room_id']),
                    'user_id' => $message_data['user_id'],
                    'updatetime' => date('Y-m-d H:i:s', time()),
                ];
                return   Gateway::sendToGroup($room_id, json_encode($new_group_message), $client_id);
            case 'C2S_ChangeLimit':
                $message = (int)$message_data['message'];
                $card = (int)$message_data['card'];
                // 获取隐私设置信息
                $db = self::getDb();
                $limit =  $db->row("SELECT * FROM `user.limit` WHERE userID = " . $_SESSION['user_id']);
                if (!empty($limit)) {
                    $db->query("UPDATE `user.limit` SET `message` = " . $message . ", `card`=" . $card . " WHERE ID =" . $limit['ID']);
                } else {
                    self::insertData('user.limit', ['message' => $message, 'card' => $card]);
                }
                $new_message = [
                    'type' => 'S2C_ChangeLimit',
                    'user_id' => $_SESSION['user_id'],
                    'message' => $message,
                    'card' => $card
                ];
                $redis = self::getRedis();
                $key = 'user_info_value_' .  $_SESSION['user_id'];
                $redis->del($key);
                if ($_SESSION['room_id']) {
                    return  Gateway::sendToGroup($_SESSION['room_id'], json_encode($new_message));
                } else {
                    return  Gateway::sendToCurrentClient(json_encode($new_message));
                }
            case 'C2S_Update_Program':
                $res = self::handleUpdateProgram($message_data);
                $all = $res['all'];
                $info = $res['info'];
                if (!empty($all)) {
                    // 发送所有未进入房间的client_id
                    $not_in_room_client_id = self::getNotInRoomClient();
                    $all_message = [
                        'type'    => 'S2C_NotIn_Admin_Room_Update',
                        'room_id' => intval($message_data['room_id']),
                        'curseat' => self::getAllRoom($message_data['room_id']),
                        'maxseat'   => 250
                    ];
                    Gateway::sendToAll(json_encode(array_merge($all_message, $all)), $not_in_room_client_id);
                }
                if (!empty($info)) {
                    $info['room_id'] = intval($message_data['room_id']);
                    $info['type'] = 'S2C_Current_Admin_Room_Update';
                    return Gateway::sendToGroup($message_data['room_id'], json_encode($info));
                }
                break;
            case 'C2S_Kick':
                $room_id         = intval($message_data['room_id']);
                $info['row']     = $message_data['row'];
                $info['col']     = $message_data['col'];
                $user_id = $message_data['user_id'];
                $clients_list = Gateway::getAllClientSessions($room_id);
                foreach ($clients_list as $tmp_client_id => $item) {
                    if ($item['user_id'] == $info['user_id']) {
                        $client_id      = $tmp_client_id;
                        $client_name    = $item['client_name'];
                        break;
                    }
                }
                // 发送所有未进入房间的client_id
                $not_in_room_client_id = self::getNotInRoomClient();
                $not_info = [
                    'type'      => 'S2C_NotInRoomUpdate',
                    'room_id'   => intval($message_data['room_id']),
                    'room_curseat' => self::getAllRoom($message_data['room_id']),
                ];
                Gateway::sendToAll(json_encode($not_info), $not_in_room_client_id);

                // 推送已进入房间
                $info['type'] = 'S2C_SelectSeatUpdate';
                $info['client_name'] = $client_name;
                $info['content']     = "踢出";
                $info['userinfo'] =  self::getUserInfo($user_id);
                Gateway::sendToGroup($room_id, json_encode($info));
                // 推送被踢的用户
                $to_client = [
                    'type'      => 'S2C_Client_Admin_Kick',
                    'user_name' => $client_name,
                ];
                self::exitRoom($clients_list[$client_id]); // 更新房间socket链接数
                return Gateway::sendToClient($client_id, json_encode($to_client));
        }
    }


    /**
     * 检查房间号是否存在
     * @return [type] [description]
     */
    public static function checkUser($user_id, $key)
    {
        if (empty($key) || empty($user_id)) {
            return false;
        }
        $db = self::getDb();
        $data = $db->row("SELECT ID as user_id,Username,Password,`Name`,Nickname,Company,Position,email,Cellphone FROM `user.user` WHERE ID = " . $user_id);

        var_export($data);

        $string = 'username:' . $data['Username'] . 'password:' . $data['Password'] . 'nickname:' . $data['Nickname'] . 'name:' . $data['Name'];

        echo $string;

        $n_key = md5($string);
        echo $n_key;

        if ($n_key != $key) {
            return false;
        }
        return true;
    }
    /**
     * 处理更改房间事件 获取房间信息
     */
    public static function handleUpdateProgram($message_data)
    {
        $db = self::getDb();
        $room_info = $db->row("SELECT `name` ,`normal`,`reporter`,`VIP`,`Activity`,`opentime`,`PicID`,`host` FROM `pltf.room` WHERE  ID = " . $message_data['room_id']);
        $pic_info  = $db->row("SELECT `url` FROM `pltf.roompic` WHERE  ID = " . $room_info['PicID']);
        $room_info['pic_url'] = $pic_info['url'];
        $steaming_info  = $db->row("SELECT `steamURL` FROM `pltf.steaming` WHERE  roomID = " . $message_data['room_id']);
        $room_info['steamURL'] = $steaming_info['steamURL'];
        $room_info['room_name'] = $room_info['name'];
        unset($room_info['PicID']);
        unset($room_info['name']);
        return ['all' => $room_info, 'info' => $room_info];
    }

    /**
     * 获取房间座位情况
     *
     * @param [type] $room_id
     */
    public static function getSeatInfo($room_id)
    {
        $db = self::getDb();
        $data =  $db->query(" SELECT  `*` FROM `pltf.seat` WHERE roomID = '" . $room_id . "' order by line asc");
        $room_seat_info = [];
        foreach ($data as $key => $value) {
            $seatdate = explode('/', $value['seatdate']);
            foreach ($seatdate as $k => $v) {
                if ($v > 0) {
                    $info = [
                        'room_id' => $room_id,
                        'user_id' => $v,
                        'row' => (int) $value['line'],
                        'col' => (int)($k + 1),
                        'userinfo' => self::getUserInfo($v)
                    ];
                    $room_seat_info[] = $info;
                }
            }
        }
        // var_export($room_seat_info);
        return $room_seat_info;
    }
    /**
     * 获取所有已开启房间信息
     *
     */
    public static function getAllRoom($room_id = '')
    {
        $db = self::getDb();
        if (empty($room_id)) {
            // 获取房间信息
            $roomData =   $db->query(" SELECT  `*` FROM `pltf.room` WHERE Activity = 1");
        } else {
            $roomData =   $db->single(" SELECT `curseat` FROM `pltf.room` WHERE ID = " . $room_id);
        }

        return $roomData;
    }
    /**
     * 获取用户信息
     *
     * @param [type] $user_id
     */
    public static function getUserInfo($user_id)
    {
        $db = self::getDb();
        $redis = self::getRedis();
        $key = 'user_info_value_' . $user_id;
        if (empty($redis->get($key))) {
            $userInfo = $db->row("SELECT ID as user_id,`Name`,Nickname,Company,Position,email,Cellphone FROM `user.user` WHERE ID = " . $user_id);
            $avterInfo = $db->row("SELECT modID FROM `user.avter` WHERE userID = " . $user_id);
            $limitInfo = $db->row("SELECT `message`,`card` FROM `user.limit` WHERE userID = " . $user_id);
            $userInfo['modid'] = $avterInfo['modID'] ?? 1;
            $userInfo['message'] = $limitInfo['message'] ?? 1;
            $userInfo['card'] = $limitInfo['card'] ?? 1;
            $redis->set($key, serialize($userInfo));
            $redis->expire($key, 10 * 60);
        } else {
            $data = $redis->get($key);
            $userInfo = unserialize($data);
        }
        return $userInfo;
    }

    /**
     * 获取未进入房间client_id
     */
    public static function getNotInRoomClient()
    {
        $client_in =  Gateway::getAllGroupClientIdList();

        // $client =  Gateway::getClientIdListByGroup(4);
        $client_in_room = [];
        array_map(function ($value) use (&$client_in_room) {
            $client_in_room = array_merge($client_in_room, array_values($value));
        }, $client_in);
        $client_all = Gateway::getAllClientIdList();

        $result =  array_diff($client_all, $client_in_room);

        return $result;
    }


    public static function updateIvtCode($user)
    {
        if (empty($user['user_id'])) {
            return false;
        }
        $db = self::getDb();
        $redis = self::getRedis();
        $key = 'ivt_code_' . $user['user_id'];
        if (empty($redis->get($key))) {
            // 获取所有已过期或未删除的数据
            // $data =  Ivtcode::find()->where(['isDelete' => 0])->andWhere(['<', 'expire', date('Y-m-d H:i:s', time())])->asArray()->all();
            $data =  $db->row("SELECT * FROM `pltf.ivtcode` WHERE `isDelete` = 0 AND binging= " . $user['user_id']);
            if (!empty($data) && $data['expire'] < date('Y-m-d H:i:s', time())) {
                // 邀请码已过期
                if ($user['room_id'] > 0) {
                    self::exitRoom($user);
                }
                if ($user['row'] > 0 && $user['col'] > 0) {
                    self::seatUpdate(3, $user);
                }
                $db->query("UPDATE `pltf.ivtcode` SET `isDelete` = 1 ,'binging' = 0 WHERE ID=" . $data['ID']);
                return false;
            }
            $redis->set($key, serialize($user));
            $redis->expire($key, strtotime($data['expire']) - time());
            return true;
        }
        return true;
    }



    /**
     * 座位状态处理
     *
     * @param [type] $status
     * @param [type] $data
     */
    public static function seatUpdate($status, $data)
    {

        $room_id = $data['room_id'];
        $user_id = $data['user_id'];
        $row = $data['row'];
        $col = $data['col'];
        $db = self::getDb();
        $redis = self::getRedis();
        // 处理数据 添加数据至 seattimeline
        $seatTimeLine = [
            'roomID' => $room_id,
            'row' => (int) $row,
            'col' => (int)$col,
            'userID' => $user_id,
            'status' => $status,
            'updatetime' => date('Y-m-d H:i:s', time())
        ];
        // $db->insert('pltf.seattimeline')->cols($seatTimeLine)->query();
        self::insertData('pltf.seattimeline', $seatTimeLine);
        if (in_array($status, ['2', '3', '5'])) {
            // 当状态 为 2 离开 ； 3 踢出  ；  5 坐下 ； 时 编辑  pltf.seat 表字座位信息
            // $roomData = $db->select('ID, line, seatdate')->from('pltf.seat')->where("roomID=" . $room_id . "AND line =" . $row)->row();
            $roomData = $db->row("SELECT ID, `line`, seatdate FROM `pltf.seat` WHERE roomID=" . $room_id . " AND `line` =" . $row);
            $lineCol = explode('/', $roomData['seatdate']);
            // $binging = $db->select('ID, line, seatdate')->from('pltf.ivtcode')->where("binging=  " . $user_id)->row();
            $binging = $db->row("SELECT ID, row, col seatdate FROM `pltf.ivtcode` WHERE binging=" . $user_id);
            if ($status == 2 || $status == 3) {
                if ($lineCol[$col - 1] == 0) {
                    $error = '当前座位不存在客户';
                    return $error;
                }
                // $col >= 1
                $lineCol[$col - 1] = 0; // 默认状态 0
                if (!empty($binging) && $binging['row'] > 0 && $binging['col'] > 0) {
                    $lineCol[$col - 1] = -1;  // 座位存在会员绑定信息 预留座位
                }
            } else {
                if ($lineCol[$col - 1] != 0) {
                    $error = '座位已存在客户或为会员预留座位';
                    return $error;
                }
                $lineCol[$col - 1] = $user_id;
            }
            $roomData['seatdate'] =  implode('/', $lineCol);
            // var_export($roomData['seatdate']);
            // 更新数据
            // $row_up = $db->update('pltf.seat')->cols($roomData)->where('ID=' . $roomData['ID'])->query();
            $db->query("UPDATE `pltf.seat` SET `seatdate` ='" . $roomData['seatdate'] . "',`updatetime`= '" . date('Y-m-d H:i:s', time()) . "' WHERE ID=" . $roomData['ID']);
        }

        return true;
    }

    /**
     * 座位信息验证
     */
    public static function verifySeat($room_id, $user_id)
    {
        // 获取数据表中座位信息
        $seatInfo =   self::getSeatInfo($room_id);
        // 获取当前房间socket链接
        $clients_list = Gateway::getAllClientSessions($room_id);
        $userId =  array_column($clients_list, 'user_id');
        if (!empty($seatInfo)) {
            var_export($seatInfo);
            foreach ($seatInfo as $val) {
                if (!in_array($val['user_id'], $userId) && $val['user_id'] != $user_id) {
                    // socket已断开，用户还存在座位信息
                    self::seatUpdate(2, $val);
                }
            }
        }
        return true;
    }

    /**
     * 退出房间
     */
    public static function exitRoom($message_data)
    {
        $room_id = $message_data['room_id'];
        $user_id = $message_data['user_id'];
        $client_id = $message_data['client_id'];
        $db = self::getDb();
        // 离开房间
        Gateway::leaveGroup($client_id, $room_id);
        // 验证座位信息
        self::verifySeat($room_id, $user_id);
        // 获取当前房间链接数
        $current = count(Gateway::getClientSessionsByGroup($room_id));
        // 获取房间最大数
        $maxseat = $db->single("SELECT maxseat FROM `pltf.room` WHERE ID=" . $room_id);
        if ($current < $maxseat) {
            $db->query("UPDATE `pltf.room` SET `curseat` =" . $current . "  WHERE ID=" . $room_id);
        }
        return true;
    }

    /**
     * 添加数据
     *
     * @param [type] $tableName
     * @param [type] $data
     */
    public static function insertData($tableName, $data)
    {
        $db = self::getDb();
        $key = implode('`,`', array_keys((array)$data));
        $value = implode("','", array_values((array)$data));
        return $db->query("INSERT INTO `" . $tableName . "` ( `" . $key . "`) VALUES ( '" . $value . "')");
    }

    /**
     * 检查房间号是否存在
     * @return [type] [description]
     */
    public static function checkroom($room_id)
    {
        if (!isset($room_id)) {
            throw new \Exception("\$room_id not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
        }
    }
    /**
     * 当客户端断开连接时
     * @param integer $client_id 客户端id
     */
    public static function onClose($client_id)
    {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id onClose:''\n";
        if (empty($_SESSION['user_id'])) {
            return;
        };
        // var_export($_SESSION);

        if (isset($_SESSION['room_id']) && !empty($_SESSION['room_id'])) {
            self::exitRoom($_SESSION);
            $not_in_room_client_id = self::getNotInRoomClient();
            $all_message = [
                'type' => 'S2C_NotInRoomUpdate',
                'room_id' => intval($_SESSION['room_id']),
                'curseat' => self::getAllRoom($_SESSION['room_id']),
            ];
            // 发送所有未进入房间的client_id
            Gateway::sendToAll(json_encode($all_message), $not_in_room_client_id);
        }
        $userSeatInfo = self::getSeatInfo($_SESSION['room_id']);
        $info = array_column($userSeatInfo, null, 'user_id');
        if (isset($info[$_SESSION['user_id']])) {
            self::seatUpdate(2, $_SESSION);
            $seat_message = [
                'type' => 'S2C_SelectSeatUpdate',
                'col' => (int)$info[$_SESSION['user_id']]['col'],
                'row' => (int) $info[$_SESSION['user_id']]['row'],
                'client_name' => $_SESSION['client_name'],
                'content' => '离座',
                'userinfo' => self::getUserInfo($_SESSION['user_id'])
            ];
            // 发送至当前房间的client_id
            Gateway::sendToGroup($_SESSION['room_id'], json_encode($seat_message));
        }
        return;
    }
}
